package org.daochong.lang;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.daochong.lang.ucm.Configuration;

@SuppressWarnings("all")
public class BeanUtil {
	static Map<String, BeanTransfer> transfers = new HashMap<String, BeanTransfer>();
	static final Map<Class<?>, BeanInfo> orms = new Hashtable<Class<?>, BeanInfo>();
	public static String DEFAULT_EXT_FLAG = "__extWithout";

	public static BeanInfo getOrmInfo(Class<?> clazz) {
		BeanInfo info = orms.get(clazz);
		if (info == null) {
			info = new BeanInfo(clazz);
			orms.put(clazz, info);
		}
		return info;
	}

	public static StackTraceElement getCallerInfo() {
		StackTraceElement[] ar = new Exception().getStackTrace();
		if (ar.length == 2)
			return ar[1];
		StackTraceElement caller = ar[1];
		for (int i = 2; i < ar.length; i++) {
			if (!ar[i].getClassName().equals(caller.getClassName())) {
				return ar[i];
			}
		}
		return caller;
	}

	public static void talbe(Class<?> clazz, String tableName) {
		if (!StringUtils.isEmpty(tableName))
			getOrmInfo(clazz).setTableName(tableName);
	}

	public static void transients(Class<?> clazz, List<String> cols) {
		getOrmInfo(clazz).setTransients(cols);
	}

	public static void keys(Class<?> clazz, List<String> keys) {
		getOrmInfo(clazz).setIds(keys);
	}

	public static void registerColMapping(Class<?> clazz, Map<String, String> mapping) {
		getOrmInfo(clazz).setColMapping(mapping);
	}

	public static void loadJpaClass(Class<?> clazz) {
		getOrmInfo(clazz);
	}

	public static Map<String, Object> toBeanMap(Map<String, Object> map) {
		if (map == null || map.size() == 0)
			return map;
		Map<String, Object> bean = new HashMap<String, Object>();
		for (String key : map.keySet()) {
			bean.put(toBeanString(key), map.get(key));
		}
		return bean;
	}

	public static Map<String, Object> toDatabaseMap(Map<String, Object> map) {
		if (map == null || map.size() == 0)
			return map;
		Map<String, Object> bean = new HashMap<String, Object>();
		for (String key : map.keySet()) {
			bean.put(toDatabaseCol(key), map.get(key));
		}
		return bean;
	}

	public static String toBeanString(String id) {
		if (StringUtils.isEmpty(id))
			return "";
		String[] ar = id.toLowerCase().split("_");
		if (ar.length == 1) {
			ar = id.toLowerCase().split("\\.");
		}
		if (ar.length == 1)
			return id.toLowerCase();
		String re = ar[0];
		for (int i = 1; i < ar.length; i++) {
			re += StringUtils.firstUpperCase(ar[i]);
		}
		return re;
	}

	public static String toDatabaseCol(String prop) {
		if (StringUtils.isEmpty(prop))
			return "";
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < prop.length(); i++) {
			char c = prop.charAt(i);
			if (c >= 65 && c <= 90) {
				sb.append('_');
				sb.append(c);
			} else if (c >= 97 && c <= 122) {
				sb.append((char) (c - 32));
			} else {
				sb.append(c);
			}
		}
		return sb.toString();
	}

	public static byte[] serializable(Object obj) {
		if (obj == null)
			return null;
		try {
			if (obj instanceof java.io.Serializable) {
				ByteArrayOutputStream bos = new ByteArrayOutputStream();
				ObjectOutputStream os = new ObjectOutputStream(bos);
				os.writeObject(obj);
				os.close();
				byte[] data = bos.toByteArray();
				bos.close();
				return data;
			} else {
				return null;
			}
		} catch (Throwable e) {
			return null;
		}
	}

	public static Object unSerializable(byte[] data) {
		if (data == null)
			return null;
		try {
			ByteArrayInputStream bis = new ByteArrayInputStream(data);
			ObjectInputStream in = new ObjectInputStream(bis);
			Object re = in.readObject();
			in.close();
			bis.close();
			return re;
		} catch (Throwable e) {
			return null;
		}
	}

	public static String serialize(Object obj) {
		if (obj == null)
			return null;
		try {
			if (obj instanceof java.io.Serializable) {
				ByteArrayOutputStream bos = new ByteArrayOutputStream();
				ObjectOutputStream os = new ObjectOutputStream(bos);
				os.writeObject(obj);
				os.close();
				byte[] data = bos.toByteArray();
				bos.close();
				return StringUtils.base64Encode(data);
			} else {
				return null;
			}
		} catch (Throwable e) {
			return null;
		}
	}

	public static Object unSerialize(String str) {
		if (str == null)
			return null;
		try {
			byte[] data = StringUtils.base64Decode(str);
			ByteArrayInputStream bis = new ByteArrayInputStream(data);
			ObjectInputStream in = new ObjectInputStream(bis);
			Object re = in.readObject();
			in.close();
			bis.close();
			return re;
		} catch (Throwable e) {
			return null;
		}
	}

	private SimpleDateFormat dateFormat = null;
	private NumberFormat numberFormat = null;
	private String encoding = null;
	private String trueString = "T";
	private String falseString = "F";
	private int bigIntegerBits = 0;

	public int getBigIntegerBits() {
		return bigIntegerBits;
	}

	public void setBigIntegerBits(int bigIntegerBits) {
		this.bigIntegerBits = bigIntegerBits;
	}

	public String getTrueString() {
		return trueString;
	}

	public void setTrueString(String trueString) {
		this.trueString = trueString;
	}

	public String getFalseString() {
		return falseString;
	}

	public void setFalseString(String falseString) {
		this.falseString = falseString;
	}

	public BeanUtil() {
		dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	}

	public String getEncoding() {
		return encoding;
	}

	public void setEncoding(String encoding) {
		this.encoding = encoding;
	}

	public void setDateFormat(String format) {
		dateFormat = new SimpleDateFormat(format);
	}

	public void setNumberFormat(NumberFormat numberFormat) {
		this.numberFormat = numberFormat;
	}

	public Object transfer(Object val, Class<?> clazz) {
		if (val == null || clazz == null)
			return null;
		Class<?> clsVal = val.getClass();
		if (clsVal.equals(clazz) || clazz.equals(java.lang.Object.class)) {
			return val;
		}
		String id = clsVal.toString() + "_" + clazz.toString();
		BeanTransfer transfer = transfers.get(id);
		if (transfer != null) {
			return transfer.transfer(val);
		}
		if (clazz.equals(java.lang.String.class)) {
			if (val instanceof Number) {
				if (this.numberFormat != null) {
					return this.numberFormat.format(val);
				}
				return String.valueOf(val);
			} else if (val instanceof java.lang.Boolean) {
				Boolean b = (Boolean) val;
				return b ? this.getTrueString() : this.getFalseString();
			} else if (val instanceof java.util.Date) {
				return dateFormat.format((Date) val);
			} else if (val instanceof byte[]) {
				try {
					return (this.getEncoding() != null ? new String((byte[]) val, this.getEncoding())
							: new String((byte[]) val));
				} catch (UnsupportedEncodingException e) {
					e.printStackTrace();
				}
			} else {
				return val.toString();
			}
		} else if (clazz.equals(java.lang.Boolean.class) || clazz.equals(boolean.class)) {
			if (val instanceof String) {
				String s = ((String) val).toUpperCase();
				return "T".equals(s) || "TRUE".equals(s);
			} else if (val instanceof Number) {
				return ((Number) val).intValue() > 0;
			}
		} else if (clazz.equals(java.lang.Integer.class) || clazz.equals(int.class)) {
			if (val instanceof Boolean) {
				Boolean b = (Boolean) val;
				return b ? 1 : 0;
			}
			try {
				return Integer.parseInt(val.toString());
			} catch (Throwable e) {
				e.printStackTrace();
			}
		} else if (clazz.equals(java.lang.Long.class) || clazz.equals(long.class)) {
			try {
				return Long.parseLong(val.toString());
			} catch (Throwable e) {
				e.printStackTrace();
			}
		} else if (clazz.equals(java.lang.Float.class) || clazz.equals(float.class)) {
			try {
				return Float.parseFloat(val.toString());
			} catch (Throwable e) {
				e.printStackTrace();
			}
		} else if (clazz.equals(java.lang.Double.class) || clazz.equals(double.class)) {
			try {
				return Double.parseDouble(val.toString());
			} catch (Throwable e) {
				e.printStackTrace();
			}
		} else if (clazz.equals(java.lang.Short.class) || clazz.equals(short.class)) {
			try {
				return Short.parseShort(val.toString());
			} catch (Throwable e) {
				e.printStackTrace();
			}
		} else if (clazz.equals(BigInteger.class)) {
			try {
				if (this.getBigIntegerBits() == 0) {
					return new BigInteger(val.toString());
				} else {
					return new BigInteger(val.toString(), this.getBigIntegerBits());
				}
			} catch (Throwable e) {
				e.printStackTrace();
			}
		} else if (isMatch(clazz, java.util.Date.class)) {
			if (val instanceof String) {
				try {
					Date date = this.dateFormat.parse((String) val);
					return date;
				} catch (Throwable e) {
					e.printStackTrace();
				}
			}
		}
		return val;
	}

	public static boolean isMatch(Class tmp, Class<?> clazz) {
		if (tmp == null)
			return false;
		if (tmp.equals(clazz))
			return true;
		try {
			if (tmp.equals(int.class) && clazz.equals(Integer.class)) {
				return true;
			} else if (clazz.equals(int.class) && tmp.equals(Integer.class)) {
				return true;
			} else if (tmp.equals(long.class) && clazz.equals(Long.class)) {
				return true;
			} else if (clazz.equals(long.class) && tmp.equals(Long.class)) {
				return true;
			} else if (tmp.equals(float.class) && clazz.equals(Float.class)) {
				return true;
			} else if (clazz.equals(float.class) && tmp.equals(Float.class)) {
				return true;
			} else if (tmp.equals(double.class) && clazz.equals(Double.class)) {
				return true;
			} else if (clazz.equals(double.class) && tmp.equals(Double.class)) {
				return true;
			} else if (tmp.equals(short.class) && clazz.equals(Short.class)) {
				return true;
			} else if (clazz.equals(short.class) && tmp.equals(Short.class)) {
				return true;
			} else if (tmp.equals(boolean.class) && clazz.equals(Boolean.class)) {
				return true;
			} else if (clazz.equals(boolean.class) && tmp.equals(Boolean.class)) {
				return true;
			}

			tmp.asSubclass(clazz);
			return true;
		} catch (Throwable e) {
			return false;
		}
	}

	public static boolean isMatch(Object o, Class<?> clazz) {
		if (o == null)
			return true;
		Class<?> tmp = o.getClass();
		return isMatch(tmp, clazz);
	}

	public static <T> T pushBean(Map<String, Object> map, Object o) {
		return new BeanUtil().push(map, o);
	}

	public static <T> T pushBean(Map<String, Object> map, Class<T> cls) {
		return new BeanUtil().push(map, cls);
	}

	public static <T> List<T> pushBeans(List<Map<String, Object>> maps, Class<T> cls) {
		return new BeanUtil().push(maps, cls);
	}

	public static Map<String, Object> popBean(Object o) {
		return new BeanUtil().pop(o);
	}

	public Map<String, String> popBeanHttpParams(Object o) {
		return new BeanUtil().popBeanHttpParams(o);
	}
	public static Map<String, Object> popWithoutNull(Object o) {
		return new BeanUtil().popBeanWithoutNull(o);
	}

	public static void copyBeanWithNotNull(Object src, Object desc) {
		if (src == null || desc == null)
			return;
		BeanInfo srcInfo = new BeanInfo(src.getClass());
		BeanInfo descInfo = new BeanInfo(desc.getClass());
		List<String> list = descInfo.getAllProperties();
		for (String prop : srcInfo.getAllProperties()) {
			Object o = srcInfo.getProperty(prop, src);
			if (o != null && list.contains(prop)) {
				descInfo.setProperty(prop, desc, o);
			}
		}
	}

	public <T> T push(Map<String, Object> map, Object obj) {
		BeanInfo beanClass = getOrmInfo(obj.getClass());
		Map<String, String> mapping = beanClass.getColMapping();
		Map<String, Object> extDatas = new LinkedHashMap<String, Object>();
		for (String key : map.keySet()) {
			String name = key;
			if (mapping != null) {
				String tmp = mapping.get(key);
				if (tmp == null) {
					for (String k : mapping.keySet()) {
						if (k.equalsIgnoreCase(key)) {
							name = mapping.get(k);
							break;
						}
					}
				}
			}
			Method m = beanClass.getPropertySet(name);
			if (m != null) {
				try {
					Class<?> clazz = m.getParameterTypes()[0];
					Object val = transfer(map.get(key), clazz);
					if (isMatch(val, clazz)) {
						m.invoke(obj, val);
					} else {
						SystemLogger.info("daochong-beanUtil", name + ":not match");
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			} else {
				Field f = beanClass.getField(name);
				if (f != null) {
					try {
						f.set(obj, transfer(map.get(name), f.getType()));
					} catch (Exception e) {
						e.printStackTrace();
					}
				} else {
					extDatas.put(name, map.get(key));
				}
			}
		}
		Method m = beanClass.getPropertySet("extDatas");
		if (m != null && beanClass.getProperty("extDatas", obj) == null) {
			Class<?>[] clazzs = m.getParameterTypes();
			if (clazzs != null && clazzs.length == 1 && (this.isMatch(extDatas, clazzs[0]))) {
				beanClass.setProperty("extDatas", obj, extDatas);
			}
		}
		return (T) obj;
	}

	public <T> T push(Map<String, Object> map, Class<T> cls) {
		BeanInfo beanClass = getOrmInfo(cls);
		Object obj = null;
		try {
			obj = cls.newInstance();
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}

		return (T) push(map, obj);
	}

	public <T> List<T> push(List<Map<String, Object>> maps, Class<T> cls) {
		List<T> list = new ArrayList<T>();
		for (Map<String, Object> map : maps) {
			list.add((T) push(map, cls));
		}
		return list;
	}

	public Map<String, Object> pop(Object o) {
		if (o == null)
			return null;
		Map<String, Object> map = new HashMap<String, Object>();
		BeanInfo c = new BeanInfo(o.getClass());
		for (Method m : c.getAllPropertiesMethod()) {
			try {
				String name = m.getName();
				String n = StringUtils.firstLowerCase((name.startsWith("get") ? name.substring(3) : name.substring(2)));
				if (c.getTransients() != null && c.getTransients().contains(name)) {
					continue;
				}

				map.put(n, m.invoke(o));
			} catch (Throwable e) {

			}
		}
		return map;
	}

	public Map<String, Object> popBeanWithoutNull(Object o) {
		if (o == null)
			return null;
		Map<String, Object> map = new HashMap<String, Object>();
		BeanInfo c = new BeanInfo(o.getClass());
		for (Method m : c.getAllPropertiesMethod()) {
			try {
				String name = m.getName();
				String n = StringUtils.firstLowerCase((name.startsWith("get") ? name.substring(3) : name.substring(2)));
				if (c.getTransients() != null && c.getTransients().contains(name)) {
					continue;
				}
				Object obj = m.invoke(o);
				if (obj != null) {
					map.put(n, obj);
				}
			} catch (Throwable e) {

			}
		}
		return map;
	}

	public Map<String, Object> popByMapping(Object o) {
		if (o == null)
			return null;
		BeanInfo c = getOrmInfo(o.getClass());
		Map<String, String> mapping = c.getColMapping();
		Map<String, Object> map = new HashMap<String, Object>();
		for (Method m : c.getAllPropertiesMethod()) {
			try {
				String name = m.getName();
				String n = StringUtils.firstLowerCase((name.startsWith("get") ? name.substring(3) : name.substring(2)));
				if (c.getTransients() != null && c.getTransients().contains(name)) {
					continue;
				}
				if (mapping != null && mapping.containsKey(name)) {
					name = mapping.get(name);
				}
				if (c.getTransients() != null && c.getTransients().contains(name)) {
					continue;
				}
				map.put(n, m.invoke(o));
			} catch (Throwable e) {

			}
		}
		return map;
	}

	public Map<String, String> popHttpParams(Object o) {
		if (o == null)
			return null;
		Map<String, String> map = new HashMap<String, String>();
		BeanInfo c = new BeanInfo(o.getClass());
		List<String> ts = c.getTransients();
		Map<String, String> mapping = c.getColMapping();
		for (Method m : c.getAllPropertiesMethod()) {
			try {
				String name = m.getName();
				String n = StringUtils.firstLowerCase((name.startsWith("get") ? name.substring(3) : name.substring(2)));
				if (c.getTransients() != null && c.getTransients().contains(name)) {
					continue;
				}
				if (mapping != null && mapping.containsKey(name)) {
					name = mapping.get(name);
				}
				if (ts != null && ts.contains(name)) {
					continue;
				}
				Object obj = m.invoke(o);
				if (obj == null) {
					map.put(n, null);
				} else {
					map.put(n, (String) transfer(obj, String.class));
				}
			} catch (Throwable e) {

			}
		}

		return map;
	}

	public static String formatString(String str, Object o) {
		Pattern p = Pattern.compile("#([\\w]+)#");
		Matcher matcher = p.matcher(str);
		StringBuffer sb = new StringBuffer();
		boolean result = matcher.find();
		BeanUtil bu = new BeanUtil();
		if (result) {
			while (result) {
				String key = matcher.group();
				Object obj = getValue(o, key);
				if (obj != null) {
					matcher.appendReplacement(sb, (String) bu.transfer(obj, String.class));
				} else {
					matcher.appendReplacement(sb, "null");
				}
				result = matcher.find();
			}
			matcher.appendTail(sb);
			str = sb.toString();
		}
		sb = new StringBuffer();
		p = Pattern.compile("\\$\\{([^\\}]+)\\}");
		matcher = p.matcher(str);
		result = matcher.find();
		if (!result) {
			return str;
		}
		while (result) {
			String key = matcher.group();
			Object obj = getValue(o, key);
			if (obj != null) {
				matcher.appendReplacement(sb, (String) bu.transfer(obj, String.class));
			} else {
				matcher.appendReplacement(sb, "null");
			}
			result = matcher.find();
		}
		matcher.appendTail(sb);
		return sb.toString();
	}

	public static Object getValue(Object obj, String id) {
		if (obj == null || StringUtils.isEmpty(id))
			return null;
		if (id.startsWith("expression:")) {
			return ExpressionFactory.getDefault().eval(id.substring(11), obj);
		}
		String prop = id;
		Object o = obj;
		if (isParameterKey(prop)) {
			String key = prop.substring(1, prop.length() - 1).trim();
			String[] ar = key.split("\\.");
			prop = ar[0].trim();
			int pos = -1;
			if (Pattern.matches("(.*)\\[\\d+\\]", prop)) {
				String tmp = prop.substring(prop.indexOf("[") + 1);
				tmp = tmp.substring(0, tmp.length() - 1);
				pos = Integer.parseInt(tmp);
				prop = prop.replaceAll("\\[\\d+\\]", "");
			}
			o = null;
			if (obj instanceof IParameter) {
				o = ((IParameter) obj).getParameter(prop);
			} else {
				BeanInfo info = new BeanInfo(obj.getClass());
				Method m = info.getMethod("getParameter", String.class);
				if (m != null) {
					try {
						m.invoke(obj, prop);
					} catch (Throwable e) {

					}
				}
			}
			if (o == null) {
				return null;
			}
			if (ar.length == 1)
				return o;
			if (pos >= 0) {
				if (o instanceof List) {
					o = ((List<?>) o).get(pos);
				} else if (o.getClass().isArray()) {
					o = ((Object[]) o)[pos];
				} else {
					return null;
				}
			}
			prop = key.substring(key.indexOf(".") + 1);
		} else if (isElKey(prop)) {
			if (prop.equals("${this}")) {
				return obj;
			}
			String key = prop.substring(2, id.length() - 1).trim();
			String[] ar = key.split("\\.");
			prop = ar[0].trim();
			int pos = -1;
			if (Pattern.matches("(.*)\\[\\d+\\]", prop)) {
				String tmp = prop.substring(prop.indexOf("[") + 1);
				tmp = tmp.substring(0, tmp.length() - 1);
				pos = Integer.parseInt(tmp);
				prop = prop.replaceAll("\\[\\d+\\]", "");
			}
			BeanInfo info = BeanUtil.getOrmInfo(obj.getClass());
			o = info.getProperty(prop, obj);
			if (o == null) {
				if (obj instanceof IAttribute) {
					o = ((IAttribute) obj).getAttribute(prop);
				}
			}
			if (o == null) {
				Method m = info.getMethod("getAttribute", String.class);
				if (m != null) {
					try {
						o = m.invoke(obj, prop);
					} catch (Throwable e) {

					}
				}
			}
			if (o == null) {
				if (id.equals("${UUID}")) {
					return uuid();
				}
			}
			if (o != null) {
				if (pos >= 0) {
					if (o instanceof List) {
						o = ((List<?>) o).get(pos);
					} else if (o.getClass().isArray()) {
						o = ((Object[]) o)[pos];
					} else {
						return null;
					}
				}
				if (ar.length == 1)
					return o;
				prop = key.substring(key.indexOf(".") + 1);
			} else {
				prop = prop.substring(2, prop.length() - 1);
			}

		} else if (isBeanKey(prop)) {
			if (obj instanceof IBean) {
				String key = prop.substring(1, prop.length() - 1).trim();
				String[] ar = key.split("\\.");
				prop = ar[0].trim();
				int pos = -1;
				if (Pattern.matches("(.*)\\[\\d+\\]", prop)) {
					String tmp = prop.substring(prop.indexOf("[") + 1);
					tmp = tmp.substring(0, tmp.length() - 1);
					pos = Integer.parseInt(tmp);
					prop = prop.replaceAll("\\[\\d+\\]", "");
				}
				o = ((IBean) obj).getBean(prop);
				if (o == null) {
					return null;
				}
				if (ar.length == 1)
					return o;
				if (pos >= 0) {
					if (o instanceof List) {
						o = ((List<?>) o).get(pos);
					} else if (o.getClass().isArray()) {
						o = ((Object[]) o)[pos];
					} else {
						return null;
					}
				}
				prop = key.substring(key.indexOf(".") + 1);
			} else {
				return null;
			}
		} else {
			return id;
		}
		if(o==null) return null;
		for (String key : prop.split("\\.")) {
			if (o instanceof Collection) {
				Collection<?> ls = (Collection<?>) o;
				if (ls.size() == 0) {
					return null;
				} else {
					o = ls.toArray()[0];
				}
			} else if (o.getClass().isArray()) {
				o = ((Object[]) o)[0];
			}

			int pos = -1;
			String[] ar = key.split("\\.");
			prop = ar[0];
			if (Pattern.matches("(.*)\\[\\d+\\]", prop)) {
				String tmp = prop.substring(prop.indexOf("[") + 1);
				tmp = tmp.substring(0, tmp.length() - 1);
				pos = Integer.parseInt(tmp);
				prop = prop.replaceAll("\\[\\d+\\]", "");
			}
			if (o instanceof Map) {
				Map map = (Map) o;
				if (map.containsKey(prop)) {
					o = map.get(prop);
				} else {
					return null;
				}
			} else {
				BeanInfo info = BeanUtil.getOrmInfo(o.getClass());
				List<String> props = info.getAllProperties();
				if (props.contains(prop)) {
					o = info.getProperty(prop, o);
				} else {
					return null;
				}
			}
			if (pos >= 0) {
				if (o instanceof List) {
					o = ((List<?>) o).get(pos);
				} else if (o.getClass().isArray()) {
					o = ((Object[]) o)[pos];
				} else {
					return null;
				}
			}
		}
		return o;
	}

	public static void setValue(Object obj, String id, String expression) {
		setValue(obj, id, getValue(obj, expression));
	}

	public static void setValue(Object obj, String id, Object value) {
		if (obj == null || StringUtils.isEmpty(id))
			return;
		String prop = id;
		Object o = obj;
		if (isParameterKey(prop)) {
			if (obj instanceof IParameter) {
				String key = prop.substring(1, prop.length() - 1).trim();
				String[] ar = key.split("\\.");
				prop = ar[0].trim();
				int pos = -1;
				if (Pattern.matches("(.*)\\[\\d+\\]", prop)) {
					String tmp = prop.substring(prop.indexOf("[") + 1);
					tmp = tmp.substring(0, tmp.length() - 1);
					pos = Integer.parseInt(tmp);
					prop = prop.replaceAll("\\[\\d+\\]", "");
				}
				if (ar.length == 1) {
					((IParameter) obj).setParameter(prop, value);
					return;
				}
				o = ((IParameter) obj).getParameter(prop);
				if (o == null) {
					return;
				}
				if (pos >= 0) {
					if (o instanceof List) {
						o = ((List<?>) o).get(pos);
					} else if (o.getClass().isArray()) {
						o = ((Object[]) o)[pos];
					} else {
						return;
					}
				}
				prop = key.substring(key.indexOf(".") + 1);
			} else {
				prop = id.substring(1, id.length() - 1);
			}
		} else if (isElKey(prop)) {
			if (obj instanceof IAttribute) {
				String key = prop.substring(2, id.length() - 1).trim();
				String[] ar = key.split("\\.");
				prop = ar[0].trim();
				if (ar.length == 1) {
					((IAttribute) obj).setAttribute(prop, value);
					return;
				}
				int pos = -1;
				if (Pattern.matches("(.*)\\[\\d+\\]", prop)) {
					String tmp = prop.substring(prop.indexOf("[") + 1);
					tmp = tmp.substring(0, tmp.length() - 1);
					pos = Integer.parseInt(tmp);
					prop = prop.replaceAll("\\[\\d+\\]", "");
				}
				o = ((IAttribute) obj).getAttribute(prop);
				if (o == null) {
					return;
				}
				if (pos >= 0) {
					if (o instanceof List) {
						o = ((List<?>) o).get(pos);
					} else if (o.getClass().isArray()) {
						o = ((Object[]) o)[pos];
					} else {
						return;
					}
				}
				prop = key.substring(key.indexOf(".") + 1);
			} else {
				prop = prop.substring(2, prop.length() - 1);
			}
		} else if (isBeanKey(prop)) {
			if (obj instanceof IBean) {
				String key = prop.substring(1, prop.length() - 1).trim();
				String[] ar = key.split("\\.");
				prop = ar[0].trim();
				int pos = -1;
				if (Pattern.matches("(.*)\\[\\d+\\]", prop)) {
					String tmp = prop.substring(prop.indexOf("[") + 1);
					tmp = tmp.substring(0, tmp.length() - 1);
					pos = Integer.parseInt(tmp);
					prop = prop.replaceAll("\\[\\d+\\]", "");
				}
				if (ar.length == 1) {
					((IBean) obj).setBean(prop, value);
					return;
				}
				o = ((IBean) obj).getBean(prop);
				if (o == null) {
					return;
				}
				if (pos >= 0) {
					if (o instanceof List) {
						o = ((List<?>) o).get(pos);
					} else if (o.getClass().isArray()) {
						o = ((Object[]) o)[pos];
					} else {
						return;
					}
				}
				prop = key.substring(key.indexOf(".") + 1);
			} else {
				prop = id.substring(1, id.length() - 1);
			}
		}
		int pos = prop.lastIndexOf('.');
		if (pos > 0) {
			o = getValue(o, prop.substring(0, pos));
			prop = prop.substring(pos + 1);
		}

		if (o instanceof Collection) {
			Collection<?> ls = (Collection<?>) o;
			if (ls.size() == 0) {
				return;
			} else {
				o = ls.toArray()[0];
			}
		} else if (o.getClass().isArray()) {
			o = ((Object[]) o)[0];
		}

		if (o instanceof Map) {
			Map map = (Map) o;
			map.put(prop, value);
		} else {
			BeanInfo info = BeanUtil.getOrmInfo(o.getClass());
			List<String> props = info.getAllProperties();
			if (props.contains(prop)) {
				info.setProperty(prop, o, value);
			}
		}
	}

	public Map<String, Object> popOrm(Object o) {
		if (o == null)
			return null;
		Map<String, Object> map = new HashMap<String, Object>();
		BeanInfo c = new BeanInfo(o.getClass());
		List<String> ts = c.getTransients();
		Map<String, String> mapping = c.getColMapping();
		for (Method m : c.getAllPropertiesMethod()) {
			try {
				String name = m.getName();
				String n = StringUtils.firstLowerCase((name.startsWith("get") ? name.substring(3) : name.substring(2)));
				if (c.getTransients() != null && c.getTransients().contains(name)) {
					continue;
				}
				if (mapping != null && mapping.containsKey(name)) {
					name = mapping.get(name);
				}
				if (ts != null && ts.contains(name)) {
					continue;
				}
				map.put(n, m.invoke(o));
			} catch (Throwable e) {

			}
		}
		return map;
	}

	public static Map<String, Object> getExtDatas(Object obj, Map<String, Object> params) {
		if (obj == null)
			return null;
		Map<String, Object> map = new LinkedHashMap<String, Object>();
		if (params == null || params.size() == 0)
			return map;
		BeanInfo info = BeanUtil.getOrmInfo(obj.getClass());
		List<String> props = info.getAllProperties();
		String extCols = (String) params.get(DEFAULT_EXT_FLAG);
		if (extCols != null) {
			List<String> extList = new ArrayList<String>();
			if (!"".equals(extCols)) {
				for (String s : extCols.split(",")) {
					extList.add(s.trim());
				}
			}
			for (String str : params.keySet()) {
				if (!props.contains(str) && !extList.contains(str) && !DEFAULT_EXT_FLAG.equals(str)) {
					map.put(str, params.get(str));
				}
			}
		}
		return map;
	}

	public static boolean isParameterKey(String key) {
		if (key == null || StringUtils.isEmpty(key)) {
			return false;
		}
		return key.startsWith("#") && key.endsWith("#");
	}

	public static boolean isBeanKey(String key) {
		if (key == null || StringUtils.isEmpty(key)) {
			return false;
		}
		return key.startsWith("@") && key.endsWith("@");
	}

	public static String uuid() {
		return UUID.randomUUID().toString().replaceAll("-", "");
	}

	public static boolean isElKey(String key) {
		if (key == null || StringUtils.isEmpty(key)) {
			return false;
		}
		return Pattern.matches("\\$\\{([^\\}]+)\\}", key);
	}

	public static void main(String[] args) throws Exception {
		AbstractContext context = new AbstractContext();
		context.setAttribute("id", "ABC");
		context.setParameter("id", "ABC");
		Configuration cfg = new Configuration();
		cfg.setConfigId("user");
		cfg.setGroupId("default");
		context.setAttribute("config", cfg);
		context.setParameter("config", cfg);

		Configuration cfg1 = new Configuration();
		cfg1.setConfigId("app");
		cfg1.setGroupId("default");
		List<Configuration> list = new ArrayList<Configuration>(1);
		list.add(cfg);
		list.add(cfg1);
		context.setAttribute("configList", list);
		context.setParameter("configList", list);
		Configuration[] ar = new Configuration[] { cfg, cfg1 };
		context.setAttribute("ar", ar);
		context.setParameter("ar", ar);
	}

	public static void test() {
		AbstractContext context = new AbstractContext();
		context.setAttribute("id", "ABC");
		context.setParameter("id", "ABC");
		Configuration cfg = new Configuration();
		cfg.setConfigId("user");
		cfg.setGroupId("default");
		context.setAttribute("config", cfg);
		context.setParameter("config", cfg);

		Configuration cfg1 = new Configuration();
		cfg1.setConfigId("app");
		cfg1.setGroupId("default");
		List<Configuration> list = new ArrayList<Configuration>(1);
		list.add(cfg);
		list.add(cfg1);
		context.setAttribute("configList", list);
		context.setParameter("configList", list);
		Configuration[] ar = new Configuration[] { cfg, cfg1 };
		context.setAttribute("ar", ar);
		context.setParameter("ar", ar);

		setValue(context, "#config.configId#", "BB");
		System.out.println(getValue(context, "#config.configId#"));

		setValue(cfg, "configId", "CC");
		System.out.println(getValue(context, "${config.configId}"));

		System.out.println(getValue(ar, "configId"));
		System.out.println(getValue(context, "1234"));
		System.out.println(getValue(context, "${id}"));
		System.out.println(getValue(context, "${config.configId}"));
		System.out.println(getValue(context, "${ar.configId}"));
		System.out.println(getValue(context, "${ar[1].configId}"));
		System.out.println(getValue(context, "${configList.configId}"));
		System.out.println(getValue(context, "${configList[1].configId}"));
		System.out.println("===================================");
		System.out.println(getValue(context, "#id#"));
		System.out.println(getValue(context, "#config.configId#"));
		System.out.println(getValue(context, "#ar.configId#"));
		System.out.println(getValue(context, "#ar[1].configId#"));
		System.out.println(getValue(context, "#configList.configId#"));
		System.out.println(getValue(context, "#configList[1].configId#"));
	}
}
